package pl.edu.pw.ee.buildcity.services;

import org.apache.log4j.Logger;
import pl.edu.pw.ee.buildcity.dao.GenericDao;
import pl.edu.pw.ee.buildcity.domain.BuildStatus;
import pl.edu.pw.ee.buildcity.entities.BuildActivity;
import pl.edu.pw.ee.buildcity.entities.SCMCommit;
import pl.edu.pw.ee.buildcity.logs.DefaultLogsHandler;
import pl.edu.pw.ee.buildcity.logs.LogsManager;

import javax.annotation.Resource;
import javax.persistence.EntityNotFoundException;
import java.util.*;

import static org.springframework.util.Assert.notNull;

/**
 * @author mgrzechocinski
 * @since 2009-10-18
 */
public class BuildActivityService extends GenericEntityService<BuildActivity, Long> {

	private static final Logger log = Logger.getLogger(BuildActivityService.class);

	@Resource(name = "jpaGenericDao")
	private GenericDao<BuildActivity, Long> dao;

	@Resource(name = "buildDefinitionService")
	private BuildDefinitionService buildDefinitionService;

	@Resource(name = "logsManager")
	private LogsManager logsManager;

	public BuildActivity registerFreshBuildActivityStart(String buildDefName) {
		return registerBuildActivity(buildDefName, Collections.<SCMCommit>emptyList());
	}

	public BuildActivity registerCodeChangedBuildActivityStart(String buildDefName, List<SCMCommit> commits) {
		return registerBuildActivity(buildDefName, commits);
	}

	private BuildActivity registerBuildActivity(String buildDefName, List<SCMCommit> commits) {
		BuildActivity newActivity = new BuildActivity().started(new Date());
		newActivity.setCommits(commits);
		newActivity.setBuildNumber(getLatestBuildNumber(buildDefName) + 1);
		newActivity.setBuildDefinition(buildDefinitionService.getByName(buildDefName));
		BuildActivity storedBuildActivity = dao.persist(newActivity);
		log.debug("New activity of build " + buildDefName + " registered: " + storedBuildActivity);
		return storedBuildActivity;
	}

	public BuildActivity registerActivityFinish(BuildActivity startedBuildActivity, BuildStatus buildStatus) {
		notNull(startedBuildActivity, "No started build activity found! Could not finish it with result " + buildStatus);
		startedBuildActivity.setResult(buildStatus);
		startedBuildActivity.ended(new Date());

		DefaultLogsHandler logHandler = logsManager.getLogHandler(startedBuildActivity.getBuildDefinition().getWorkingCopy());
		log.debug("LogHandler: " + logHandler);
		if (logHandler != null) {
			startedBuildActivity.setBuildLog(logHandler.getLogs());
		}

		BuildActivity finishedBuildActivity = dao.merge(startedBuildActivity);
		log.info("Found started activity and successfully set it's finish with result " + buildStatus + ": " + finishedBuildActivity);
		return finishedBuildActivity;
	}

	public List<BuildActivity> getLatestBuildActivities(String buildDefName, int numberOfActivitiesToFetch) {
		try {
			HashMap<String, Object> params = new HashMap<String, Object>();
			params.put("name", buildDefName);
			return dao.executeNamedQuery("findAllBuildActivitiesOfBuildDefinition", params, numberOfActivitiesToFetch);
		} catch (EntityNotFoundException e) {
			return Collections.emptyList();
		}
	}

	/**
	 * @param buildDefName
	 * @return
	 */
	private Integer getLatestBuildNumber(String buildDefName) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("name", buildDefName);

		Integer latestBuildNumber = 0;
		try {
			BuildActivity lastBuildActivity = dao.executeNamedQuery("findAllBuildActivitiesOfBuildDefinition", params).get(0);
			latestBuildNumber = lastBuildActivity.getBuildNumber();
		} catch (EntityNotFoundException e) {
			log.warn("Could not find latest activity of " + buildDefName + ". Considered as first activity, so latest build number is " + latestBuildNumber);
		}
		return latestBuildNumber;
	}
}
